﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Deployment.Application;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using RG.Common;
using RG.Common.Configuration;
using RG.Common.Const;
using RG.Common.WPF.Commands;
using RG.Common.WPF.Dialogs;
using RG.Common.WPF.Settings;
using Microsoft.Practices.Unity;
using RG.Common.Configuration;

namespace RG.Common.WPF.Workplaces
{
    [SupportDataBinding]
    public partial class SingleFrameWorkplace : IWorkplace
    {
        [Dependency]
        public IUnityContainer Cfg { get; set; }

        private readonly WpfSettings settings;
        private readonly Stack<Window> openedDialogs = new Stack<Window>();

        private WpfSettings frameSettings;
        private object frameVM;

        private const string defMsg = "Ожидание...";

        public string StateMsg { get; set; }
        public bool IsProgres { get; set; }
        private bool ByUpdateClosing;
        public ICommand RebootCmd { get; set; }
        public ICommand HoldCmd { get; set; }

        public long MinVal { get; set; }
        public long MaxVal { get; set; }
        public long CurVal { get; set; }
        public string NewVer { get; set; }
        public TimeSpan MessageDuration { get; set; }
        private bool isMessageShow;
        public bool IsMessageShow
        {
            get { return isMessageShow; }
            set
            {
                isMessageShow = value;
                //если попап закрт не по кнопке отложить то 
                //откладываем перезапуск программы на 5 минут 
                if(!isMessageShow && !ByUserHolded)
                {
                    StateMsg = "Перезапуск отложен на 5 мин, если вы все сохранили то можете перезапустить программу вручную";
                    Log.Info("Пользователь не попал в окно сообщения, отложили перезагрузку на 5 минут ...");
                }
            }
        }

        public bool ByUserHolded { get; set; }

        private string holdTime;
        public string HoldTime
        {
            get { return holdTime; }
            set
            {
                holdTime = value;
                switch (holdTime)
                {
                    case "30 мин":
                        MessageDuration = new TimeSpan(0, 30, 0);
                        break;
                    case "60 мин":
                        MessageDuration = new TimeSpan(1, 0, 0);
                        break;
                    default:
                        MessageDuration = new TimeSpan(0, 15, 0);
                        break;
                }
            }
        }
        internal static readonly log4net.ILog Log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        public SingleFrameWorkplace()
        {
            StateMsg = defMsg;
            HoldTime = "15 мин";
            IsProgres = false;
            InitializeComponent();
            settings = new WpfSettings();
            settings.Bind("MainWindow", this);
            settings.Load();
            DataContext = this;

            // Попытка обработки когда при старте не видно главного окна (у меня в настройках были записаны непонятные цифры -32050)
            if (Top < 0) Top = 0;
            if (Left < 0) Left = 0;
            
            RebootCmd = new DelegateCommand(DoClose);
            HoldCmd = new DelegateCommand(DoHold);
        }

        public void DoClose()
        {
            //разница как оказалось в том что ярлык запускает не экзешку а путь где искать обновление
            //надо как то деликатно впендюрить его сюда, проблема в том что проверить получиться только после publish'a 
            //System.Diagnostics.Process.Start(Application.ResourceAssembly.Location, "-ms");
            System.Diagnostics.Process.Start(ApplicationDeployment.CurrentDeployment.UpdateLocation.ToString(), "-ms");
            Log.Info("Перезапускаемся ...");
            ByUpdateClosing = true;
            Close();
        }

         private void DoUpdateProgress(object sender, DeploymentProgressChangedEventArgs e)
        {
            CurVal = e.BytesCompleted;
            Log.Info(String.Format("Скачано {0} из {1}", e.BytesCompleted, e.BytesTotal));
            UpdateLayout();
        }

        public void DoHold()
        {
            Log.Info(string.Format("Пользователь отложил перезагрузку на {0} ...", MessageDuration));
            StateMsg = string.Format("Перезапуск отложен на {0}, если вы все сохранили то можете перезапустить программу вручную", HoldTime);
            //обязательно говорим что оложили специально 
            //перед тем как попап гасить
            ByUserHolded = true;
            IsMessageShow = false;
        }

        protected IView<TPresenter> CreateView<TPresenter>(TPresenter presenter)
        {
            var v = Cfg.Resolve<IView<TPresenter>>();
            v.Presenter = presenter;
            return v;
        }

        #region Implementation of IWorkplace Переопределение методов интерфейса IWorkplace

        public void Show<TPresenter>(TPresenter presenter)
        {
            var frame = (UserControl) CreateView(presenter);
            MainGrid.Children.Clear();
            MainGrid.Children.Add(frame);
            
            frameSettings = new WpfSettings();
            frameSettings.BindToTypeName(frame);
            frameSettings.Load();

            frameVM = presenter;
        }

        public void Close(object presenter)
        {
            MainGrid.Children.Clear();
        }

        public bool ShowDialog<TPresenter>(TPresenter presenter, string caption)
        {
            var dwVM = Cfg.Resolve<DialogWindowVM>();
            dwVM.SetChild(presenter);

            var w = (Window) CreateView(dwVM);
            if (caption != "") w.Title = caption;

            var windowSettings = new WpfSettings();
            var settingsKey = w.GetType().Name;
            var child = presenter as IChildView;
            while (child != null)
            {
                settingsKey = child.Child.GetType().Name;
                child = child.Child as IChildView;
            }
            windowSettings.Bind(settingsKey, w);
            windowSettings.Load();
            
            openedDialogs.Push(w);

            var r = (bool)w.ShowDialog();
            openedDialogs.Pop();

            windowSettings.Save();
            return r;
        }

        public bool ShowEditableDialog<TEditableObject>(TEditableObject presenter, string caption) where TEditableObject : IEditableObject
        {
            var editor = Cfg.Resolve<EditableObjectDlgVM>();
            editor.SetChild(presenter);
            return ShowDialog(editor, caption);
        }

        public bool ShowEditableDialog<TEditableObject>(TEditableObject presenter, string caption,string okText,string cancelText) where TEditableObject : IEditableObject
        {
            var editor = Cfg.Resolve<EditableObjectDlgVM>();
            editor.OkText = okText;
            editor.CancelText = cancelText;
            editor.SetChild(presenter);
            return ShowDialog(editor, caption);
        }

        public void ShowAlarm<TalarmManager>(TalarmManager frame, int id)
        {
            
        }

        public void CloseAlarm()
        {
            
        }

        delegate void closeDelegate(Window w);
        public void CloseDialog(bool isOk)
        {
            var w = openedDialogs.Peek();

            Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                                   new closeDelegate(
                                       x =>
                                           {
                                               x.DialogResult = isOk; // Забавно, но судя по всему сеттер DialogResult ещё и пытается закрыть диалог, так что Close делать не надо
                                               //x.Close();
                                           }), w);
        }

        public void Shutdown()
        {
            Close();
        }

        public void Error(string errorText)
        {
            MessageBox.Show(errorText, "Ошибка", MessageBoxButton.OK,MessageBoxImage.Error);
        }

        public void Information(string infoText)
        {
            MessageBox.Show(infoText, "Внимание", MessageBoxButton.OK, MessageBoxImage.Information);
        }

        public bool? Ask(string askText)
        {
            var r = MessageBox.Show(askText, "Вопрос", MessageBoxButton.YesNoCancel,MessageBoxImage.Question);
            if (r == MessageBoxResult.Yes) return true;
            if (r == MessageBoxResult.No) return false;
            return null;
        }

        public string SelfScreen()
        {
            var renderTargetBitmap = new RenderTargetBitmap(
                (int)SystemParameters.FullPrimaryScreenWidth,
                (int)SystemParameters.FullPrimaryScreenHeight,
                96, 96, PixelFormats.Pbgra32);
            renderTargetBitmap.Render(this);
            // Сохранение. Вместо renderTargetBitmap можно передать любой BitmapSource
            var jpegBitmapEncoder = new JpegBitmapEncoder {QualityLevel = 100};
            jpegBitmapEncoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
            var fileName = string.Format(@"{0}\Screenshot.jpg", Path.GetTempPath());
            if (File.Exists(fileName))
                File.Delete(fileName);
            var fileStream = new FileStream(fileName, FileMode.CreateNew);
            jpegBitmapEncoder.Save(fileStream);
            fileStream.Close();
            return fileName;
        }


        public bool AskYesNo(string askText)
        {
            return MessageBox.Show(askText, "Вопрос", MessageBoxButton.YesNo,MessageBoxImage.Question) == MessageBoxResult.Yes;
        }

        public void PrintReport<TFactory, T>(T initVal, ReportPaperSize reportPaperSize /*bool isPortret*/) where TFactory : IReportfactoryBase<T>
        {
 
        }

        public string SaveReport<TFactory, T>(T initVal, ReportPaperSize reportPaperSize /*bool isPortret*/) where TFactory : IReportfactoryBase<T>
        {
            return "";
        }


        public void PrintReportFromFile(string path,string name)
        {
            
        }

        public event EventHandler ReportPrintPressed;

        #endregion

        private void MainWindow_Closing(object sender, CancelEventArgs e)
        {
            if (frameSettings != null) frameSettings.Save();
            if (settings != null) settings.Save();
            if (!ByUpdateClosing)
            {
                if (!AskYesNo("Вы уверены, что хотите закрыть окно программы?"))
                {
                    e.Cancel = true;
                    return;
                }
            }
            
            if (frameVM != null)
            {
                if (frameVM is IWorkplaceObject)
                {
                    var obj = (IWorkplaceObject)frameVM;
                    e.Cancel = !obj.CanClose;
                }
            }
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            //вместо того чтобы сразу ломиться за обновлениями запускаем таймер 
            //DoCheckUpdate(this, null);
        }
    }
}